#include <bits/stdc++.h>
using namespace std;

const int N = 1005;
const int dx[4] = {-1, 1, 0, 0}; // x方向变化：上、下、左、右
const int dy[4] = {0, 0, -1, 1}; // y方向变化：上、下、左、右

char grid[N][N];     // 存储网格数据
int potential[N][N]; // 记录每个位置作为清除目标能带来的额外开垦数

int main() {
  int n, m;
  scanf("%d%d", &n, &m);

  // 读取网格数据，从1开始索引，方便边界处理
  for (int i = 1; i <= n; i++) {
    scanf("%s", grid[i] + 1);
  }

  int baseCount = 0; // 不进行任何清除时的开垦数

  // 遍历每个格子
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
      int obstacleCount = 0;      // 周围杂物数量
      int obstacleDirection = -1; // 如果有且仅有一个杂物，记录其方向

      // 检查四个方向
      for (int k = 0; k < 4; k++) {
        if (grid[i + dx[k]][j + dy[k]] == '#') {
          obstacleCount++;
          obstacleDirection = k;
        }
      }

      // 当前是荒地的情况
      if (grid[i][j] == '.') {
        if (obstacleCount == 0) {
          // 周围没有杂物，可以直接开垦
          baseCount++;
        } else if (obstacleCount == 1) {
          // 只有一个杂物，清除该杂物可以使当前荒地可开垦
          int x = i + dx[obstacleDirection];
          int y = j + dy[obstacleDirection];
          potential[x][y]++;
        }
      }
      // 当前是杂物的情况
      else if (grid[i][j] == '#' && obstacleCount == 0) {
        // 如果清除这个杂物，且周围没有其他杂物，可以开垦
        potential[i][j]++;
      }
    }
  }

  // 找到清除一个杂物能带来的最大额外开垦数
  int maxAdditional = 0;
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
      int num = 0, p = -1;
      for (int k = 0; k < 4; k++)
        if (grid[i + dx[k]][j + dy[k]] == '#')
          num++, p = k;
      if (grid[i][j] == '.' && num == 1)
        a[i + dx[p]][j + dy[p]]++;
      maxAdditional = max(maxAdditional, potential[i][j]);
    }
  }

  // 总开垦数 = 基础开垦数 + 最大额外开垦数
  cout << baseCount + maxAdditional << endl;
  return 0;
}